/**
 * Created by ${PRODUCT_NAME}.
 * User: skylerparr
 * Date: 1/22/11
 * Time: 12:13 PM
 * To change this template use File | Settings | File Templates.
 */
package com.thoughtorigin.meta {
import com.thoughtorigin.meta.MetaType;
import com.thoughtorigin.meta.MetaType;
import com.thoughtorigin.meta.MetadataWorker;
import com.thoughtorigin.reflect.Describe;
import com.thoughtorigin.reflect.MetaDataItem;
import com.thoughtorigin.reflect.MetaReader;

import com.thoughtorigin.util.Instantiator;

import flash.utils.getQualifiedClassName;
import flash.utils.setTimeout;

public class RefreshMetaData implements MetaType {

    private var _metaReader: MetaReader;
    private var _metadataWorker: MetadataWorker;
    private var _counter: int;
    private var _instantiator: Instantiator;

    public function RefreshMetaData() {
    }

    public function decorate(object:Object, metadata:MetaDataItem, callback:Function):void {
        var refreshFunc: Function = function(decoratedObject: Object, thiscallback: Function): void {
            _metaReader.populateMetaData(Describe.type(_instantiator.getClassByName(getQualifiedClassName(decoratedObject))), function(): void {
                refreshData(decoratedObject, _metaReader, thiscallback);
            });
        }

        object[metadata.decoratedPropertyName] = refreshFunc;
        callback.call(this);
    }

    private function refreshData(decoratedObject: Object, metaReader: MetaReader, completeCallback: Function): void {
        _counter = 0;
        for(var key: String in metaReader.classMetaData.propertyMetaData) {
            var metaItem: Array = _metaReader.classMetaData.propertyMetaData[key];
            for each(var item: MetaDataItem in metaItem) {
                //this is how many items that will be refreshed.  call the complete callback function
                // when the counter reaches zero again.
                //todo: This is a little brittle.  Assuming the metadata is going to be called "Data" forever
                if(item.metaDataName == "Data") {
                    _counter++;
                    redecorateData(item, decoratedObject, completeCallback);
                }
            }
        }
    }

    private function redecorateData(item: MetaDataItem, decoratedObject: Object, completeCallback: Function): void {
        setTimeout(function(): void {
            var type: MetaType = _metadataWorker.metaTypes["Data"];
            type.decorate(decoratedObject, item, function(): void {
                _counter--;
                isComplete(completeCallback);
            });
        }, 0);

    }

    private function isComplete( complete: Function):void {
        if(_counter == 0) {
            complete.call(this);
        }
    }

    public function preprocess(clazz:Class, metadata:MetaDataItem):void {
    }

    public function get priority():int {
        return 0;
    }

    [Inject]
    public function set metaReader(value: MetaReader): void {
        _metaReader = value;
    }

    [Inject]
    public function set metadataWorker(value: MetadataWorker): void {
        _metadataWorker = value;
    }

    [Inject]
    public function set instantiator(value: Instantiator): void {
        _instantiator = value;
    }

    public function dispose(... args):void {
        _metaReader = null;
    }
}
}
